﻿using System;
using System.Diagnostics.Contracts;
using EuroManager.Domain.Simulator.Engine.Movements;
using EuroManager.Domain.Simulator.Helpers;

namespace EuroManager.Domain.Simulator.Engine
{
    [ContractClass(typeof(SteeringContract))]
    public interface ISteering : ITimeAware
    {
        Vector2D Location { get; }
        
        Vector2D Velocity { get; }
        
        Vector2D Heading { get; }
        
        float Speed { get; }
        
        IMovement Movement { get; }
        
        void Turn(Vector2D target);
        
        void Move(IMovement movement);
        
        void Stop();

        void Halt();
        
        void Hit(Vector2D startVelocity);
        
        void Meet(Vector2D destination, float tolerance, float time);
        
        void Arrive(Vector2D destination, float tolerance);
    }

    [ContractClassFor(typeof(ISteering))]
    public abstract class SteeringContract : ISteering
    {
        public abstract Vector2D Location { get; }

        public abstract Vector2D Velocity { get; }

        public abstract Vector2D Heading { get; }

        public abstract float Speed { get; }

        public abstract IMovement Movement { get; }

        public abstract void Update(float elapsedTime);

        public abstract void Turn(Vector2D target);

        public void Move(IMovement movement)
        {
            Contract.Requires(movement != null);
        }

        public abstract void Stop();

        public abstract void Halt();

        public abstract void Hit(Vector2D startVelocity);

        public void Meet(Vector2D destination, float tolerance, float time)
        {
            Contract.Requires(tolerance.IsRational() && tolerance >= 0);
            Contract.Requires(time.IsRational() && time >= 0);
        }

        public void Arrive(Vector2D destination, float tolerance)
        {
            Contract.Requires(tolerance.IsRational() && tolerance >= 0);
        }
    }
}
